#include "mbed.h"
#include "max31865.h"
#include "pid.h"
#define  delay_us  wait_us
#define uint unsigned int
#define uchar unsigned char
//------------------------------------
// Hyperterminal configuration
// 9600 bauds, 8-bit data, no parity
//------------------------------------
PwmOut mypwm3(PC_9);//PC_9
PwmOut mypwm1(PA_15);//PC_9
PwmOut mypwm2(PB_7);//PC_9
Serial pc(SERIAL_TX, SERIAL_RX);

DigitalOut led1(LED1);

DigitalOut mypin(PC_0);
DigitalOut mosfet_ctrl(PC_8);
DigitalOut mlx90614_SCL(PB_3);
DigitalInOut mlx90614_SDA(PA_10);
Ticker pidTicker;
Ticker filterTicker;
char tempH,tempL,err;
/**********************************************************************************************************
定义max31865温度采样寄存器数组
**********************************************************************************************************/
const unsigned int temp_adc_code[46]={
        1517,       2394,       3254,       4101,       4936,       5762,       6579,       6903,       7227,       7550,
//  		-200        -175        -150        -125        -100        -75         -50         -40         -30         -20     
        7871,       8192,       8512,       8830,       9148,       9465,       9781,       10096,  10410,  10723,
//  		-10         0               10          20          30          40          50          60          70          80
        11035,  11346,  11657,  11966,  12274,  12582,  12888,  13194,  13498,  13802,
//  		90          100         110         120         130         140         150         160         170         180
        14104,  14406,  15156,  15901,  16639,  17371,  18098,  18818,  19533,  20242,
//  		190         200         225         250         275         300         325         350         375         400
        20945,  21642,  22333,  23018,  23697,  24370
//  		425         450         475         500         525         550
};


/**********************************************************************************************************
max31865温度采样寄存器数组序号与实际温度对应函数
**********************************************************************************************************/
int order_to_temp(int order_number)  
{
        int t;
        switch(order_number)
        {
            case 0: t=-200;break;
            case 1: t=-175;break;
            case 2: t=-150;break;
            case 3: t=-125;break;
            case 4: t=-100;break;
            case 5: t=-75;break;
            case 6: t=-50;break;
            case 7: t=-40;break;
            case 8: t=-30;break;
            case 9: t=-20;break;
            case 10: t=-10;break;
            case 11: t=0;break;
            case 12: t=10;break;
            case 13: t=20;break;
            case 14: t=30;break;
            case 15: t=40;break;
            case 16: t=50;break;
            case 17: t=60;break;
            case 18: t=70;break;
            case 19: t=80;break;
            case 20: t=90;break;
            case 21: t=100;break;
            case 22: t=110;break;
            case 23: t=120;break;
            case 24: t=130;break;
            case 25: t=140;break;
            case 26: t=150;break;           
            case 27: t=160;break;
            case 28: t=170;break;
            case 29: t=180;break;
            case 30: t=190;break;           
            case 31: t=200;break;
            case 32: t=225;break;
            case 33: t=250;break;
            case 34: t=275;break;
            case 35: t=300;break;
            case 36: t=325;break;
            case 37: t=350;break;           
            case 38: t=375;break;
            case 39: t=400;break;
            case 40: t=425;break;
            case 41: t=450;break;               
            case 42: t=475;break;
            case 43: t=500;break;           
            case 44: t=525;break;
            case 45: t=550;break;           
        
        }
        return t;
}
    

/**********************************************************************************************************
max31865温度转换函数
**********************************************************************************************************/
unsigned char bottom=0,top=46;
double compute_temp(unsigned int adc_code,unsigned int bottom,unsigned int top)
{
    int t_top,t_bottom;
    double a,b,t_current_buf;
    if((top-bottom)/2==0)
    {
			t_top=order_to_temp(top);   //top ¶ÔÓ¦µÄÎÂ¶È
      t_bottom=order_to_temp(bottom); //bottom ¶ÔÓ¦µÄÎÂ¶È
      a=(t_top-t_bottom)/(double)(temp_adc_code[top]-temp_adc_code[bottom]); //a=(t1-t2)/(x1-x2)
      b=t_top-a*temp_adc_code[top];
      t_current_buf=a*adc_code+b;  //y=ax+b
      return t_current_buf;
    }
    else if(adc_code<=temp_adc_code[(top-bottom)/2+bottom])
    {
        t_current_buf=compute_temp(adc_code,bottom,(top-bottom)/2+bottom);
    }else if(adc_code>temp_adc_code[(top-bottom)/2+bottom])
    {
        t_current_buf=compute_temp(adc_code,(top-bottom)/2+bottom,top);
    }
    return t_current_buf;
}

/**********************************************************************************************************
设置PWM输出函数
**********************************************************************************************************/
void setPWM(char chx,float Pwm)
{
	int pulse;
	pulse = Pwm * 10000;
	switch(chx)
	{
		case 1:mypwm1.pulsewidth_us(pulse);	break;
		case 2:mypwm2.pulsewidth_us(pulse);	break;
		case 3:mypwm3.pulsewidth_us(pulse);	break;
	}
}
/**********************************************************************************************************
获取max31865温度函数
**********************************************************************************************************/
float getTemp(char chx)
{
	return ((double)(compute_temp((max31865_read_data(chx,0x01)<<7)+(max31865_read_data(chx,0x02)>>1),0,46)));
}

unsigned int max31865_adc_code;
int t_pulsewidth=10,t_period=10,t_best_pulsewidth;
double t_current;
/**********************************************************************************************************
定义PID结构体
**********************************************************************************************************/
	struct _PID{
	double Error0;
	double Error1;
	double Error2;
	double Pwm0;
	double Pwm1;
	double PidP;
	double PidI;
	double PidD;
	double SetT;
	char Channel;
	};
struct _PID spid1,spid2,spid3;
/**********************************************************************************************************
PID初始化函数
**********************************************************************************************************/
void PIDInit(void)
{
  spid1.Error0=0;
	spid1.Error1=0;
	spid1.Error2=0;
	spid1.Pwm0=0;
	spid1.Pwm1=0;
	spid1.PidP=0.1;
	spid1.PidI=0.001;
	spid1.PidD=0.001;
	spid1.SetT=120;
	spid1.Channel=1;
	
  spid2.Error0=0;
	spid2.Error1=0;
	spid2.Error2=0;
	spid2.Pwm0=0;
	spid2.Pwm1=0;
	spid2.PidP=0.1;
	spid2.PidI=0.0005;
	spid2.PidD=0.001;
	spid2.SetT=120;
	spid2.Channel=2;	
	
  spid3.Error0=0;
	spid3.Error1=0;
	spid3.Error2=0;
	spid3.Pwm0=0;
	spid3.Pwm1=0;
	spid3.PidP=0.1;
	spid3.PidI=0.0005;
	spid3.PidD=0.001;
	spid3.SetT=120;
	spid3.Channel=3;
}
/**********************************************************************************************************
PID 各个参数设置，温度设置函数
**********************************************************************************************************/
void PIDSingleSet(struct _PID *spid,char kx,uint kdata)
{
	double kdata_tmp=0;
	kdata_tmp=kdata/1000000.0;
		switch(kx)
		{
			case 	'p':	spid->PidP=kdata_tmp;break;
			case 	'i':	spid->PidI=kdata_tmp;break;
			case 	'd':	spid->PidD=kdata_tmp;break;
			case	't':spid->SetT=kdata;break;
			
		}
		pc.printf("%c %d %f\r\n",kx,spid->Channel,kdata_tmp);
		return;
}
/**********************************************************************************************************
PID控制函数
**********************************************************************************************************/
float PIDCtrl(struct _PID *spid)	
{	
	double cTemp=0;
	cTemp=getTemp(spid->Channel);
	spid->Error0 = spid->SetT - cTemp;

	switch(spid->Channel)
	{
		case 1:	pc.printf("current_temp1 %f\n\r", cTemp);
						break;
		case 2:	pc.printf("current_temp2 %f\n\r", cTemp);
						break;
		case 3:	pc.printf("current_temp3 %f\n\r", cTemp);	
						break;
	}	
	
	//spid->Pwm0	 = spid->Pwm1 + (spid->PidP + spid->PidI)* spid->Error0 - spid->PidP * spid->Error1;	//原PID计算公式
	//Pwm0	 = Pwm1 + (PidP + PidI+PidD)* Error0 -(PidP + 2*PidD)* Error1+ PidD*Error2; //原 PI 计算公式
	spid->Pwm0	 = spid->Pwm1 + (spid->PidP + spid->PidI+ spid->PidD)* spid->Error0 - (spid->PidP+spid->PidD*2) * spid->Error1+spid->PidD*spid->Error2;
	spid->Error1 = spid->Error0;
	spid->Error2 = spid->Error1;			
	if(spid->Pwm0 >1)
		spid->Pwm0 =1;
	else if (spid->Pwm0 <0)
		spid->Pwm0 = 0;		
	spid->Pwm1 = spid->Pwm0;
	setPWM(spid->Channel,spid->Pwm1);
	return spid->Pwm1;
}
/**********************************************************************************************************
PID参数串口输出打印函数
**********************************************************************************************************/
uchar pidSetFlag=0;
void pidPrint(void)
{
		pc.printf("p1 %f\r\n",spid1.PidP);
		pc.printf("i1 %f\r\n",spid1.PidI);
		pc.printf("d1 %f\r\n",spid1.PidD);
		pc.printf("t1 %f\r\n",spid1.SetT);
		pc.printf("p2 %f\r\n",spid2.PidP);
		pc.printf("i2 %f\r\n",spid2.PidI);
		pc.printf("d2 %f\r\n",spid2.PidD);
		pc.printf("t2 %f\r\n",spid2.SetT);
		pc.printf("p3 %f\r\n",spid3.PidP);
		pc.printf("i3 %f\r\n",spid3.PidI);
		pc.printf("d3 %f\r\n",spid3.PidD);
		pc.printf("t3 %f\r\n",spid3.SetT);
		return;	
}
/**********************************************************************************************************
mls90614 初始化函数
**********************************************************************************************************/
void mlx90614_init()              //初始化
{
	 mlx90614_SDA.output(); 
		mlx90614_SCL=1;
		delay_us(2);
		mlx90614_SCL=0;  //切换到SMBUS模式
		delay_us(150); 
		mlx90614_SCL=1;
		delay_us(2);	
		mlx90614_SDA=1;
		delay_us(2);
}
/**********************************************************************************************************
mls90614 开始函数
**********************************************************************************************************/
void mlx90614_start()         //启动信号
{
	 mlx90614_SDA.output(); 
		mlx90614_SCL=0;
		 delay_us(2);
		mlx90614_SDA=1;
		 delay_us(2);	
		mlx90614_SCL=1;
		 delay_us(2);
		mlx90614_SDA=0;
		 delay_us(2);
//		mlx90614_SCL=0;
//		 delay_us(2);	
}
/**********************************************************************************************************
mls90614 停止函数
**********************************************************************************************************/
void mlx90614_stop()            //停止信号
{
	 mlx90614_SDA.output(); 
    mlx90614_SCL=0;
      delay_us(2);
		mlx90614_SDA=0;
      delay_us(2);

		mlx90614_SCL=1;
     delay_us(2);

		mlx90614_SDA=1;
     delay_us(2);
}
/**********************************************************************************************************
mls90614 字节发送函数
**********************************************************************************************************/
void mlx90614_sendbyte(uchar data)  //       写一个字节
{

     uchar i;  
			mlx90614_SDA.output();	
     for(i=0;i<8;i++)
     {  

			 mlx90614_SCL=0;
       delay_us(2);

				if((data<<i)&0x80)
				{
					mlx90614_SDA.write(1);
					delay_us(2);
				}else if(((data<<i)&0x80)==0)
				{
					mlx90614_SDA.write(0);
					delay_us(2);
				}

			 mlx90614_SCL=1;
       delay_us(2);

     }
//			mlx90614_SCL=0;
//			delay_us(2);		 
//			mlx90614_SDA=0;
}
/**********************************************************************************************************
mlx90614 读取响应函数
**********************************************************************************************************/
void  read_ack()
{

	mlx90614_SCL=0;
	delay_us(2);
	mlx90614_SDA.output();
	mlx90614_SDA=0;
  delay_us(2); 
	mlx90614_SCL=1;
  delay_us(2);
	mlx90614_SCL=0;
  delay_us(2); 
	
}

/**********************************************************************************************************
mlx90614 字节读取函数
**********************************************************************************************************/
uchar mlx90614_readbyte(void)
{
	 uchar  bit_buf=0;
    uchar read_temp,i;  
			
			mlx90614_SDA.input();  
     for(i=0;i<8;i++)
     {  
       
			 mlx90614_SCL=0;
       delay_us(2);
       
			 mlx90614_SCL=1;
       delay_us(2);
       read_temp<<=1;
			 bit_buf=mlx90614_SDA.read();		
       read_temp+=bit_buf;
			 delay_us(2);
     }
		
    return read_temp; 

}
/**********************************************************************************************************
发送响应函数
**********************************************************************************************************/
void send_ack(void)
{
    int i=0;
	 
	mlx90614_SCL=0;
	delay_us(2);
	mlx90614_SDA=0;
	mlx90614_SDA.input();	

	delay_us(2);
	mlx90614_SCL=1; 
	delay_us(2);
	mlx90614_SCL=0;
	delay_us(2);	
	while((0==mlx90614_SDA.read())&&(i++<10))
	{};	
	delay_us(2);
}
/**********************************************************************************************************
mlx90614温度读取函数
**********************************************************************************************************/
float readtemp(uchar chx)
{

  mlx90614_start();
  mlx90614_sendbyte(0x00);  //元件地址
  send_ack();
  mlx90614_sendbyte(chx);   //寄存器地址
  send_ack(); 
  mlx90614_start();					
  mlx90614_sendbyte(0x01);	//读命令
  send_ack();
  tempL=mlx90614_readbyte();
  read_ack();
  tempH=mlx90614_readbyte();
  read_ack();
  err=mlx90614_readbyte();
  read_ack();
  mlx90614_stop();
  return((tempH*256+tempL)/50.0-273.15);
}


/**********************************************************************************************************
pid处理中断函数
**********************************************************************************************************/


char led1Flag=0,tickerFlag=0;

void pidHandler()
{
		tickerFlag=1;
//		led1Flag=(led1Flag==0?1:0);
//		led1=((led1Flag&0x01)?1:0);
}



/**********************************************************************************************************
滤波中断处理函数
**********************************************************************************************************/
float AA1 = 0.999;
float BB1 = 0.001;
float T0 = 0;
float T1 = 0;
float t0 = 0;
float t1 = 0;

void filterHandler()
{
		T1 = T0;
		t1 = t0;
		T0 = readtemp(0x07);
		t0 = T1 * BB1 + t1 * AA1;
}




/**********************************************************************************************************
串口pid设置中断处理函数
**********************************************************************************************************/
double pidCycle=0.1;
uchar pidCycleFlag=0;
char cmd_tmp,no_tmp,getc_tmp,number_tmp;
unsigned char	rstate=0;
unsigned int data_tmp=0;
void echouart()
{
	switch(rstate)
	{
		case	0: 	cmd_tmp=pc.getc();
							if(cmd_tmp=='p'||cmd_tmp=='i'||cmd_tmp=='d'||cmd_tmp=='t'||cmd_tmp=='c')//t 温度；c 采样周期
								rstate=1;
							else rstate=0;						
		case	1:  no_tmp=pc.getc();
							if((no_tmp=='1'||no_tmp=='2'||no_tmp=='3')&&(cmd_tmp=='p'||cmd_tmp=='i'||cmd_tmp=='d'||cmd_tmp=='t'||cmd_tmp=='c'))
							{
								number_tmp=no_tmp;
								rstate=2;
							}else if(no_tmp==' ')
							{
								rstate=3;
							}
							else rstate=0;
							break;
		case 	2:	if(pc.getc()==' ')
								rstate=3;
							else rstate=0;
							break;
		case	3:	getc_tmp=pc.getc();
							if(getc_tmp>='0'&&getc_tmp<='9')
							{
									data_tmp=data_tmp*10+(getc_tmp-'0');
									rstate=3;
							}else if(getc_tmp=='\r')
							{
								rstate=4;
							}else rstate=0;
							break;
		case	4: 	getc_tmp=pc.getc();
							if(getc_tmp=='\n')
							{
								if(cmd_tmp=='p'||cmd_tmp=='i'||cmd_tmp=='d'||cmd_tmp=='t')
								{
									
									switch(number_tmp)
									{
										case '1':	PIDSingleSet(&spid1,cmd_tmp,data_tmp);break;
										case '2':	PIDSingleSet(&spid2,cmd_tmp,data_tmp);break;
										case '3':	PIDSingleSet(&spid3,cmd_tmp,data_tmp);break;
									}
									pidSetFlag=1;
									
								}
								if(cmd_tmp=='c')
								{
									pidCycle=data_tmp/1000.0;
									pidCycleFlag=1;
								
								}
							//	pc.printf("%c%c %f\r\n",cmd_tmp,no_tmp,data_tmp/1000000.0);
								data_tmp=0;
							}
							rstate=0;
							break;
		
	}
	while(pc.readable())
	{
		pc.getc();
	}		
			
}

/**********************************************************************************************************
主函数
**********************************************************************************************************/
int main() 
{
  unsigned char temp_set;
  long i = 1;
  unsigned int temp_buf,temp_adc_code;
	double pulse_buf;
	pc.attach(&echouart,SerialBase::RxIrq);  //定义串口接收中断
	pidTicker.attach(&pidHandler,0.1);				//定义PID处理中断;
	filterTicker.attach(&filterHandler,0.001);
  max31865_init();
  max31865_write_data(1,0x80,0x00);         //Auto Mode, 3-Wire, 50Hz
	wait_ms(70);
  max31865_write_data(3,0x80,0x00);         //Auto Mode, 3-Wire, 50Hz
	wait_ms(70);
	max31865_write_data(2,0x80,0x00);         //Auto Mode, 3-Wire, 50Hz
  wait_ms(70);
  max31865_write_data(1,0x80,0xd1);         //Auto Mode, 3-Wire, 50Hz
	wait_ms(70);
  max31865_write_data(3,0x80,0xd1);         //Auto Mode, 3-Wire, 50Hz
	wait_ms(70);
	max31865_write_data(2,0x80,0xd1);         //Auto Mode, 3-Wire, 50Hz
  wait_ms(70);
	mypwm1.period_us(10000);
	mypwm2.period_us(10000);
	mypwm3.period_us(10000);
	PIDInit();
//	timerTempCtrl.attach(&severTempCtrl,0.1);
	mlx90614_init();
	float temp1;
	uchar bit_buf1;
	long tavr=0;
	double tavr1;
	double temp=0,wtemp=0,PWMC;
	pidPrint();
  while(1) 
  {
		
//		PIDSingleSet(&spid1,'p',1000000);  //pid控制 pid设置，c周期设置 t温度设置
//		temp1=readtemp(0x07);
			if(pidSetFlag)
			{
				pidSetFlag=0;
				pidPrint();	
			}
			if(pidCycleFlag)
			{
				pidCycleFlag=0;			
				pidTicker.attach(&pidHandler,pidCycle);
				pc.printf("%c %f \r\n",'c',pidCycle);
			}
			if(tickerFlag)		//  每pidCycle时间 执行一次pid运算 
			{
				tickerFlag=0;
				PIDCtrl(&spid1);
				PIDCtrl(&spid2);
				PIDCtrl(&spid3);
			}
//			temp1=readtemp(0x06);
//			pc.printf("temp6 %f\n\r",temp1);
//			
//			temp1=readtemp(0x07);
//			pc.printf("temp7 %f\n\r",temp1);
			
			pc.printf("temp7 %f\n\r",t0);
			pc.printf("temp6 %f\n\r",T0);
	}
}
 